package de.fhd.pms.dao;

import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import de.fhd.pms.dto.AutoDTO;
import de.fhd.pms.model.Auto;
import de.fhd.pms.model.Fahrt;

/**
 * The Data access class for {@link Auto} objects. DAO encapsulates all accesses
 * to the data source, including construction and dismantling of the connection.
 * All Interaction with the database regarding the entity bean {@link Auto}
 * should be handled by this class! Its tasks:
 * <ul>
 * <li>set new objects of the class</li>
 * <li>modify or delete an object of the class</li>
 * <li>deliver all objects of the class</li>
 * <li>further functions in context to the class objects</li>
 * </ul>
 * 
 * @author Josef Fischer
 * @author Alexander Neetzel
 * @author Philipp Six
 */
public class AutoDao extends HibernateDaoSupport {

	/**
	 * 
	 * Creates a new {@link Auto} and saves it in the DB for JUnitTesting.
	 * 
	 * @param marke
	 */
	public void create(String marke) {
		Auto a = new Auto(marke);
		save(a);
	}

	/**
	 * Returns a single {@link Auto} object by its id
	 * 
	 * @param id
	 *            the primary key of {@link Auto}
	 * @return a single {@link Auto}
	 */
	public Auto findById(int id) {
		HibernateTemplate template = getHibernateTemplate();
		return (Auto) template.get(Auto.class, id);
	}

	/**
	 * Returns all {@link Auto} objects from the DB
	 * 
	 * @return a list of {@link Auto} objects
	 */

	public List<Auto> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		return template.loadAll(Auto.class);
	}

	/**
	 * Saves {@link Auto} object specified by the parameter in the DB
	 * 
	 * @param auto
	 *            is the object that'll be saved in the DB
	 * @return a {@link Auto} object
	 */
	public Auto save(Auto auto) {
		HibernateTemplate template = getHibernateTemplate();
		template.saveOrUpdate(auto);
		return auto;
	}

	/**
	 * Deletes the specified {@link Auto} object from the DB
	 * 
	 * @param auto
	 *            the object to be deleted
	 * @throws DeleteException
	 *             if the specified {@link Auto} is included in a {@link Fahrt}
	 */
	@SuppressWarnings("rawtypes")
	public void delete(Auto auto) throws DeleteException {
		HibernateTemplate template = getHibernateTemplate();
		List fahrtenVonAuto = template.find("FROM Fahrt f where f.auto like "
				+ auto.getId());
		if (fahrtenVonAuto.size() == 0) {
			template.delete(auto);

		} else {
			throw new DeleteException(
					"Das Auto darf nicht gelöscht werden, da es bereits verwendet wurde.");
		}
	}

	/**
	 * Creates a DTO-Set of {@link Auto} objects
	 * 
	 * @param
	 * @return a Set of {@link Auto} objects
	 */
	private Set<AutoDTO> createDtoSet(List<Auto> autos) {
		Set<AutoDTO> results = new TreeSet<AutoDTO>();
		for (Auto a : autos) {

			results.add(new AutoDTO(a.getId(), a.getCreated(), a.getBaujahr(),
					a.getFarbe(), a.getKennzeichen(), a.getKm(), a.getMarke(),
					a.getModell(), a.getTarif(), a.getStation().getStrasse()));
		}
		return results;
	}

	/**
	 * Returns the list of Auto objects which are currently not on a trip. The
	 * method works as follows:
	 * <ul>
	 * <li>An HQL query is specified and stored in a String variable</li>
	 * <li>Retrieve all Auto objects from the DB</li>
	 * <li>Create an empty list for the results and empty Auto objects</li>
	 * </ul>
	 * 
	 * @return a Set of {@link Auto} objects
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<AutoDTO> findAvailable() {
		HibernateTemplate template = getHibernateTemplate();
		return (Set<AutoDTO>) template.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(Auto.class);
				criteria.add(Restrictions.isNotNull("station"));
				List<Auto> alleAutos = criteria.list();
				return createDtoSet(alleAutos);
			}
		});
	}
}